package com.horizon.cloud.seckill.service.impl;


import javax.annotation.Resource;
import java.beans.Transient;
import java.util.concurrent.TimeUnit;

public class RedisSeckillServiceImpl {
    //秒杀商品的DAO数据库操作类
    @Resource
    SeckillSkuDao seckillSkuDao;

    //秒杀订单的DAO数据库操作类
    @Resource
    SeckillOrderDao seckillOrderDao;

    //商品分段数据库操作类
    @Resource
    SeckillSegmentStockDao seckillSegmentStockDao;

    //redis分布式锁实现类
    @Autowired
    RedisLockService redisLockService;

    //执行秒杀下单
    public SeckillOrderDTO executeSeckill(SeckillDTO inDto) {
        String exposedKey = inDto.getExposedKey();
        String cacheSkuId = redisRepository.getStr("seckill:sku:"+exposedKey);
        if(null == cacheSkuId) {
            throw BusinessException.builder().errMsg("秒杀没有开启或者已经结束");
        }

        long skuId = Long.parseLong(cacheSkuId);
        Long userId = inDto.getUserId();

        Long res = redisRepository.executeScript(
                getSeckillScript(),
                Collections.singletonList("checkToken"),
                intDto.getExposedKey(),
                String.valueOf(intDto.getUserId()),
                inDto.getSeckillToken());

        if(res !=5) {
            throw BusinessException.builder().errMsg("请提前排队").build();
        }

        //创建订单对象
        SeckillOrderPO order = SeckillOrderPO.builder()
                .skuId(skuId).userId(userId).build();
        Date nowTime = new Date();
        order.setCreateTime(nowTime);
        order.setStatus(SeckillConstants.ORDER_VALID);

        SeckillOrderDTO dto = null;

        //创建重复性检查的订单对象
        SeckillOrderPO checkOrder = SeckillOrderPO.builder().skuId(
                order.getSkuId()).userId(order.getUserId()).build();

        //记录秒杀订单信息
        long insertCount = seckillOrderDao.count(Example.of(checkOrder));

        //唯一性判断:skuId, id保证一个用户只能秒杀一件商品
        if(insertCount>=1) {
            //重复秒杀
            throw;
        }

        int stockLeft = seckillSegmentStockDao.sumStockCountById(skuId);
        if(stockLeft<=0) {
            throw
        }

        //获取分布式锁
        String lockKey = "seckill:segmentLock:" + String.valueOf(skuId);
        String requestId = getDefaultRequestId();
        JedisMultiSegmentLock lock = redisLockService.getSegmentLock(
                lockKey, requestId,SEGEMENT_DEFAULT
        );
        boolean hasError = false;
        boolean locked = false;
        try{
            //执行秒杀,秒杀前先抢到分布式锁
            locked = lock.trLock(1, TimeUnit.SECONDS);
        } catch (InterruptedException e) {

        }

        if(locked) {
            try{
            //进入秒杀事务
            //执行秒杀逻辑1.减分段库存（没有扣减总库存）2.下秒杀订单
            doInTransaction(order, lock);
            dto= new SeckillOrderDTO();
            BeanUtils.copyProperties(order, dto);

         } catch (Exception e) {
            e.printStackTrace();
            hasError = true;

        } finally {
            /**
             * 释放分布式锁
             */
            lock.unlock();
        }

    }

        if (!locked || hasError) {
        throw BusinessException.builder().errMsg("执行秒杀，发生异常").build();
    }

        return dto;
    }

    @Transactional
    public void doInTransaction(SeckillOrderPO order,
                                JedisMultiSegmentLock lock) {
        long skuId = order.getSkuId();
        //插入秒杀订单
        seckillOrderDao.save(order);

        //减分段库存
        int segment = lock.getSegmentIndexLocked();
        seckillSegmentStockDao.decreaseStock(skuId, segment);

        //减库存
        seckillSkuDao.updateStockCountById(skuId);
    }
}
